package com.legsem.jrhosync.ws.rs;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;

import junit.framework.TestCase;

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpMethodBase;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.InputStreamRequestEntity;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.RequestEntity;
import org.codehaus.jackson.JsonGenerator;
import org.codehaus.jackson.map.MappingJsonFactory;
import org.codehaus.jackson.map.ObjectMapper;

import com.legsem.jhosync.Constants;
import com.legsem.jhosync.Server;

public abstract class AbstractResourceITCase extends TestCase {

    private HttpClient _client;
    private ObjectMapper _mapper = new ObjectMapper();
    private MappingJsonFactory _jsonFactory = new MappingJsonFactory();

    public static final String JHOSYNC_ROOT_URL = "http://localhost:8080/jhosync.samples";

    public void setUp() throws Exception {
        _client = new HttpClient();
        postJSONRequest("/login", "{\"login\":\"" + Constants.ADMIN_LOGIN
                + "\",\"password\":\"" + "" + "\"}");
        String api_token = new String(postJSONRequest("/api/get_api_token",
                "{}"));
        postJSONRequest("/api/reset", "{\"api_token\":\"" + api_token + "\"}");
        postJSONRequest("/logout", "{}");
    }

    public byte[] postJSONRequest(final String relativeURL,
            final Object valueObject) throws IOException {
        PostMethod method = new PostMethod(JHOSYNC_ROOT_URL + relativeURL);
        method.addRequestHeader(Server.LOG_CORRELATION_ID, this.getName());

        method.setRequestEntity(getRequestEntity(valueObject));
        return execMethod(method);

    }

    public byte[] getJSONRequest(final String relativeURL) throws IOException {
        GetMethod method = new GetMethod(JHOSYNC_ROOT_URL + relativeURL);
        method.addRequestHeader(Server.LOG_CORRELATION_ID, this.getName());
        return execMethod(method);
    }

    public byte[] execMethod(final HttpMethodBase method) throws IOException {
        try {
            method.addRequestHeader("Accept", "text/plain, application/json");

            int returnCode = _client.executeMethod(method);

            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            byte[] byteArray = new byte[4096];
            int count = 0;
            while ((count = method.getResponseBodyAsStream().read(byteArray, 0,
                    byteArray.length)) > 0) {
                outputStream.write(byteArray, 0, count);
            }

            if (returnCode != HttpStatus.SC_OK) {
                throw new IOException("Request returned:" + returnCode
                        + " message:"
                        + new String(outputStream.toByteArray(), "UTF-8"));
            } else {
                return outputStream.toByteArray();
            }
        } finally {
            method.releaseConnection();
        }

    }

    /**
     * Encapsulate an object in an HTTP client entity containing a JSON
     * serialization of the object.
     * 
     * @param valueObject the java object
     * @return an HTTP client request entity
     * @throws IOException if object cannot be mapped to JSON
     */
    public RequestEntity getRequestEntity(final Object valueObject)
            throws IOException {
        if (valueObject instanceof String) {
            return new InputStreamRequestEntity(new ByteArrayInputStream(
                    ((String) valueObject).getBytes("UTF-8")),
                    "application/json");
        } else {
            ByteArrayOutputStream osba = new ByteArrayOutputStream();
            OutputStreamWriter osw = new OutputStreamWriter(osba, "UTF-8");
            JsonGenerator jsonGenerator = _jsonFactory.createJsonGenerator(osw);
            _mapper.writeValue(jsonGenerator, valueObject);
            osw.close();
            return new InputStreamRequestEntity(new ByteArrayInputStream(
                    osba.toByteArray()), "application/json");
        }
    }

    public ObjectMapper getMapper() {
        return _mapper;
    }

    public MappingJsonFactory getJsonFactory() {
        return _jsonFactory;
    }

}
